"""
交叉验证解释：
    概述：
        交叉验证是一种更完善、可信度更高的模型评估方法、其思路：把训练集分成N份，每次都取1份作为验证集。其他作为训练集。
        然后计算模型评分.
        思路：
            把训练集分成N份 例如：分成4份 -》也叫4折交叉验证
            第1次，把第一份数据作为验证集（测试集），其他作为训练集，训练模型，模型预测，获取：准确率->准确率1
            第2次，把第二份数据作为验证集（测试集），其他作为训练集，训练模型，模型预测，获取：准确率->准确率2
            第3次，把第三份数据作为验证集（测试集），其他作为训练集，训练模型，模型预测，获取：准确率->准确率3
            第4次，把第四份数据作为验证集（测试集），其他作为训练集，训练模型，模型预测，获取：准确率->准确率4
            然后计算上述4次准确率平均值 ，作为模型最终准确率

        情况1：无独立测试集（2）时
                交叉验证完后，若已经确定最优模型（通过网络搜索找到最优参数）
                需要使用全部原始数据（没有划分训练和测试），重新训练模型，此时模型将学习整个数据集模式。

        情况2：有独立测试集（2）时
                交叉验证仅用于训练集内部的调优，最终更需要未参与的数据与交叉验证的独立测试集模型评估泛化能力。
                避免数据窥探（20%测试集）

    网络搜索
        目的：
            寻找最优超参
        超参：
            用户手动录入数据
    大白话解释：
        网络搜索+交叉验证 ，本质GridSearchCV这个API

"""

from sklearn.datasets import load_iris  # 加载鸢尾花数据集(150条数据)
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, GridSearchCV  # 分割训练集和测试集 (8:2 7:3)
from sklearn.preprocessing import StandardScaler  # 数据标准化
from sklearn.neighbors import KNeighborsClassifier  # KNN算法 分类对象 因为鸢尾花是分类的场景 ，采用三分法
from sklearn.metrics import accuracy_score  # 模型评估 计算模型准确率
import seaborn as sns

# 1、加载鸢尾花数据集
iris_data = load_iris()

# 2、数据预处理
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=22)

# 3、特征工程之子工程_特征预处理（标准化） 演示！！因为源数据不存在量纲问题
# 3.1 创建标准化对象
transfer = StandardScaler()
# 3.2 对特征列进行标准化  x_train：训练集特征  训练+转换
x_train = transfer.fit_transform(x_train)
# 3.3 处理测试集  transform只有转换
x_test = transfer.transform(x_test)

# 4、模型训练
# 4-1 实例化模型
es = KNeighborsClassifier()  # 注意 ，不要传递超参了！！！！

# 4-2  定义字典  记录：超参可能出现情况
parm_dict = {'n_neighbors': [i for i in range(1, 20)]}

# 4-3 创建GridSearchCV对象 -》寻找最优超参
es = GridSearchCV(es, parm_dict, cv=4)

# 4-4 具体模型训练动作
es.fit(x_train, y_train)

# 4.5打印最优的超参组合
print(f"最优评分:{es.best_score_}")  # 最优组合的平均分
print(f"最优超参组合:{es.best_params_}")  # 最优超参组合（供参考）
print(f"最优的估计器对象:{es.best_estimator_}")  # 最优组合的模型对象
print(f"具体交叉验证结果:{es.cv_results_}")  # 所有组合的 评估结果（过程）

# 5、再次评估模型 （冗余写法）
# es=KNeighborsClassifier(n_neighbors=3)
# es.fit(x_train,y_train)
# y_pre=es.predict(x_test)
# print(f"准确率:{accuracy_score(y_test,y_pre)}")

# 5、再次评估模型 （非冗余写法）
y_pre2 = es.best_estimator_.predict(x_test)  # 直接使用模型最优参数预测
print(f"准确率:{accuracy_score(y_test, y_pre2)}")
